Qt is a C++ cross-platform application and user-interface framework. It is developed by Nokia and contains a comprehensive library of GUI classes.
Using the visual editor “Qt Designer” GUIs are easily created and maintained.
This notebook describes a simple method to integrate Qt GUIs in Python programs using PyQt and the Python module QtGuiLoader.
In Example 1 a simple but flexible widget is created. It can be used as Widget, Dialog or MainWindow.
In Exercise 1 the widget is extended with more stuff to control a plot
Install a distribution, e.g. Pythonxy, winpython or Anaconda
or
Install Python 2.7, Qt4 (including QtDesigner), and PyQt4 (alternatively PySide)
In this example a simple but flexible widget is created. It can be used as Widget, Dialog or MainWindow (Menubar, toolbar and statusbar cannot be added to this widget).
"Horizontal Layout" from the "Widget Box" and drop it on the Form"LineEdit" to layout"PushButton" to layout next to the "LineEdit"pushButtonclicked()actionPrintTexttrigger()MyUI/MyWidgetUI.ui" in the same folder as this notebookMyUI/MyWidgetUI.py" file in the same folder (This is required in order to import the widget. Its content will be autogenerated if the file is completely empty or older than "MyUI/MyWidgetUI.ui")The widget can be integrated as QMainWindow, QDialog or QWidget.
QMainWindow is a separate window, i.e. two main windows can be closed independently. QDialog is a sub window, i.e. if its parent window is closed the dialog is closed too. A dialog may be modal, such that other windows cannot be operated before the dialog is closed. QWidget can be inserted into an existing widget or layout.In order to use it, subclass QtMainWindowLoader, QtDialogLoader or QtWidgetLoader from QtGuiLoader and instantiate with MyUI.MyWidgetUI as ui_module argument.
When using QtGuiLoader, actions are by default connected to methods with the same name.
All PyQt elements are found in the self.ui-object, e.g. self.ui.lineEdit and documentation of the PyQt elements is found at http://pyqt.sourceforge.net/Docs/PyQt4/classes.html
In the following script, MYWidgetUI is used as a QMainWindow. Run it using Shift-Enter.
A new window will open and the text in the QLineEdit will be printet when clicking the QPushButton
In [ ]:
import MyUI.MyWidgetUI
from QtGuiLoader import QtMainWindowLoader
class MyMainWindow(QtMainWindowLoader):
def __init__(self):
QtMainWindowLoader.__init__(self, ui_module=MyUI.MyWidgetUI)
def actionPrintText(self):
print "Mainwindow text: %s"%str(self.ui.lineEdit.text())
print #required to print at first click (only when running as IPython Notebook)
MyMainWindow().start()
In the following example MyWidgetUI is reused as both QMainWindow, QDialog and QWidget.
On some platforms you need to close the window opened in the previous script before running the next script
In [ ]:
from QtGuiLoader import QtMainWindowLoader, QtDialogLoader, QtWidgetLoader
import MyUI.MyWidgetUI
from PyQt4 import QtGui
class MyMainWindow(QtMainWindowLoader):
def __init__(self):
QtMainWindowLoader.__init__(self, ui_module=MyUI.MyWidgetUI)
self.setWindowTitle("Mainwindow")
#Add as QWidget
self.ui.horizontalLayout.addWidget(MyWidget(self))
#Add button that opens as QDialog
self.ui.horizontalLayout.addWidget(QtGui.QPushButton("Open dialog", self, clicked=self.open_dialog))
def open_dialog(self):
#open as QDialog
MyDialog(parent=self,modal=True).start()
def actionPrintText(self):
print "Mainwindow text: %s"%self.ui.lineEdit.text()
class MyDialog(QtDialogLoader):
def __init__(self,parent,modal):
QtDialogLoader.__init__(self, MyUI.MyWidgetUI, parent, modal)
self.setWindowTitle("Dialog")
def actionPrintText(self):
print "Dialog text: %s"%self.ui.lineEdit.text()
class MyWidget(QtWidgetLoader):
def __init__(self, parent):
QtWidgetLoader.__init__(self, ui_module=MyUI.MyWidgetUI, parent=parent)
self.show()
def actionPrintText(self):
print "Widget text: %s"%str(self.ui.lineEdit.text())
print #required to print at first click (only when running as IPython Notebook)
MyMainWindow().start()
Add "Form Layout" to "Form"
x:
formLayout and add an entry for x:QLineEdit (default)xLineEdit and set properties in Property editor:y:
QLineEdit (default) yxLineEdit and set properties in Property editor:Color:
formLayout again and add entry for color:QComboBoxcolorComboBox and add three items:Width:
formLayout again and add entry for width:QLineEdit (default) widthLineEdit (The one you just added)"Horizontal Layout""Horizontal Slider" to horizontal layouthorizontalSlider and set properties in Property editor:"Label" next to horizontalSliderformLayout again and add entry for yLim:QLineEdit (default) yLimLineEdit (The one you just added)"Horizontal Layout""Spin Box" to horizontal layoutspinBox and set properties in Property editor:Label next to spinBoxalignHCenter"Double Spin Box" next to labeldoubleSpinBox and set properties in Property editor:| Sender | Signal | Receiver | Slot |
| `xLineEdit` | editingFinished() | acitonUpdatePlot | trigger() |
| `yLineEdit` | editingFinished() | acitonUpdatePlot | trigger() |
| `colorComboBox` | currentIndexChanged(int) | acitonUpdatePlot | trigger() |
| `horizontalSlider` | sliderReleased() | acitonUpdatePlot | trigger() |
| `spinBox` | valueChanged(int) | acitonUpdatePlot | trigger() |
| `doubleSpinBox` | valueChanged(double) | acitonUpdatePlot | trigger() |
MyUI/MyPlotControlUI.ui" in the same folder as this notebookMyUI/MyPlotcontrolUI.py" file in the same folder (This is required in order to import the widget. Its content will be autogenerated if the file is completely empty or older than "MyUI/MyPlotControlUI.ui")Hints:
self.ui.yLineEdit. The text must be converted to a string using str(x)QAbstractSlider(super class of QSlider). See link in top of the QSlider documentationspinBox and the upper bound from doubleSpinBoxRun again
In [ ]:
import MyUI.MyPlotControlUI
from QtGuiLoader import QtMainWindowLoader
import numpy as np
import matplotlib.pyplot as plt
class MyPlotControlMainWindow(QtMainWindowLoader):
def __init__(self):
try: self.ui = MyUI.MyPlotControlUI.Ui_Form() # Enables autocompletion (maybe...)
except: pass
QtMainWindowLoader.__init__(self, ui_module=MyUI.MyPlotControlUI)
#Connect widget signals to actionUpdatePlot
self.ui.xLineEdit.editingFinished.connect(self.actionUpdatePlot)
self.ui.yLineEdit.editingFinished.connect(self.actionUpdatePlot)
self.ui.colorComboBox.currentIndexChanged.connect(self.actionUpdatePlot)
self.ui.horizontalSlider.valueChanged.connect(self.actionUpdatePlot)
self.ui.spinBox.valueChanged.connect(self.actionUpdatePlot)
self.ui.doubleSpinBox.valueChanged.connect(self.actionUpdatePlot)
self.actionUpdatePlot()
x_str = property(lambda self : str(self.ui.xLineEdit.text()))
y_str = property(lambda self : "x")
color = property(lambda self : 'Red')
width = property(lambda self : 1)
ylim = property(lambda self : (0,10))
def actionUpdatePlot(self):
print (self.x_str, self.y_str, self.color, self.width, self.ylim)
MyPlotControlMainWindow().start()
In [ ]: